package nacos

import (
	"fmt"
	"gitee.com/ymofen/gobase"
	"gitee.com/ymofen/golang/strmap"
	"gitee.com/ymofen/nacos/pkg/subpub"
	"gitee.com/ymofen/refobjects"
	"sync"
)

type NacosCfgReader struct {
	closedFlag int8
	conf       string
	confMap    strmap.StrMap
	clientRef  *refobjects.RefWrapper
	configId   string
	groupId    string

	lk sync.RWMutex

	lsHandle interface{}
	sp       *subpub.SubPub
}

func NewNacosCfgReader(conf string) (*NacosCfgReader, error) {
	confMap := strmap.NewStrMap()
	confMap.URLFormDecode(conf)
	if _, ok := confMap["conn.type"]; !ok {
		confMap["conn.type"] = "nacosCfgClient"
	}
	clientConf := confMap.URLEncode0Prefix("conn.", true)
	r, err := refobjects.Acquire(clientConf)
	if err != nil {
		return nil, err
	}

	rd := &NacosCfgReader{conf: conf, confMap: confMap}
	rd.clientRef = r
	rd.configId = confMap["configId"]
	rd.groupId = confMap["groupId"]
	return rd, nil
}

func (this *NacosCfgReader) ReadValue(args ...interface{}) (v interface{}, err error) {
	clt := this.clientRef.Object.(*NacosConfigClient)
	confRawStr, err := clt.GetConfig(this.configId, this.groupId)
	if err != nil {
		return "", err
	}
	return confRawStr, nil
}

func (this *NacosCfgReader) onConfigChanged(namespace, group, dataId, data string) {
	this.sp.Publish("DATA", data)
}

func (this *NacosCfgReader) checkCloseLs() error {
	this.lk.RLock()
	ls := this.lsHandle
	this.lk.RUnlock()
	if ls == nil { // 已经关闭
		return nil
	}

	clt := this.clientRef.Object.(*NacosConfigClient)
	err := clt.CancelListenConfig(ls)
	if err != nil {
		return err
	}

	this.lk.Lock()
	this.lsHandle = nil
	this.lk.Unlock()

	return nil

}

func (this *NacosCfgReader) checkSubscribe() error {
	this.lk.RLock()
	sp := this.sp
	this.lk.RUnlock()
	if sp != nil {
		return nil
	}

	this.lk.Lock()
	defer this.lk.Unlock()
	if this.sp != nil {
		return nil
	}

	if this.closedFlag == 1 {
		return fmt.Errorf("closed NacosCfgReader")
	}

	clt := this.clientRef.Object.(*NacosConfigClient)
	hd, err := clt.ListenConfig(this.configId, this.groupId, this.onConfigChanged)
	if err != nil {
		return err
	}
	this.lsHandle = hd
	this.sp = subpub.NewSubPub()
	return nil

}

func (this *NacosCfgReader) Subscribe(cb func(topic string, args ...interface{})) (subHandle interface{}, err error) {
	err = this.checkSubscribe()
	if err != nil {
		return nil, err
	}

	subHandle = this.sp.Subscribe("DATA", cb)
	return
}

func (this *NacosCfgReader) CancelSubscribe(subHandle interface{}) (err error) {
	return this.sp.Unsubscribe(subHandle)
}

func (this *NacosCfgReader) Close() error {
	this.lk.Lock()
	this.closedFlag = 1
	this.lk.Unlock()

	rf := this.clientRef
	if rf != nil {
		this.clientRef = nil
		return rf.Close()
	}
	return nil
}

func CreateNacosCfgReaderForFactory(args ...interface{}) (interface{}, error) {
	return NewNacosCfgReader(args[0].(string))
}

func init() {
	gobase.RegisterFactoryCreateFunc("nacosCfgReader", CreateNacosCfgReaderForFactory)
}
